﻿#include "Container.h"

//#ifdef _MSC_VER
//#include <inttypes.h>
//#endif
#include "Express.h"
#include "InstrumentData.h"
#include "Tick.h"
#include "DataTypes.h"
#include "../Log/logging.h"
#include <boost/algorithm/string.hpp>
//#include "DatabaseOperator.h"
//#include "Express.h"
#include "InstrumentConfig.h"
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
// int AfxCompareVariantValue( int nVariantID, CInstrumentInfo & info1, CInstrumentInfo &info2,
// 						   CInstrumentContainer * pContainer )
// {
// 	long	x1 = 0, x2 = 0;
// 	double	d1 = 0., d2 = 0.;
// 	bool	bGet1 = FALSE, bGet2 = FALSE;
// 
// 	switch( nVariantID )
// 	{
// 	case	SLH_CODE:						//	股票代码
// 		return strcmp( info1.GetInstrumentID(), info2.GetInstrumentID() );
// 	case	SLH_NAME:						//	股票名称
// 		return strcmp( info1.GetInstrumentName(), info2.GetInstrumentName() );
// 		//	技术数据
// 	case	SLH_DATE:						//	日期
// 		return ( info1.m_datetech- info2.m_datetech );
// 	case	SLH_DATE_BEGIN:					//	上市日期
// 		return strcmp( info1.OpenDate, info2.OpenDate );
// 		//	主要基本指标
// // 	case	SLH_REPORTTYPE=:					// 报表类型
// // 		return dwordcmp( info1.m_reporttype, info2.m_reporttype );
// 	case	SLH_PE:							//	市盈率
// 	case	SLH_PNETASSET:					//	市净率
// 	case	SLH_PMAININCOME:				//	市销率
// // 	case	SLH_RATIO=_PCASH:				//	价格净现金比
// // 		bGet2	=	AfxGetVariantValue( nVariantID, info2, &d2, pContainer );
// // 		bGet1	=	AfxGetVariantValue( nVariantID, info1, &d1, pContainer );
// // 		if( !bGet2 && !bGet1 )
// // 			return 0;
// // 		if( !bGet2 )	return 1;
// // 		if( !bGet1 )	return -1;
// // 		if( d1 < 0 && d2 < 0 )
// // 			return doublecmp( d1, d2 );
// // 		if( d1 < 0 )			return 1;
// // 		if( d2 < 0 )			return -1;
// // 		return doublecmp( d1, d2 );
// // 	case	SLH_TRADE=:						// 行业
// // 		return strcmp( info1.GetStockDomain(), info2.GetStockDomain() );
// // 	case	SLH_PROVINCE=:					// 省份
// // 		return strcmp( info1.GetStockProvince(), info2.GetStockProvince() );
// 	default:
// // 		bGet2	=	AfxGetVariantValue( nVariantID, info2, &d2, pContainer );
// // 		bGet1	=	AfxGetVariantValue( nVariantID, info1, &d1, pContainer );
// // 		if( !bGet2 && !bGet1 )
// // 			return 0;
// // 		if( !bGet2 )	return 1;
// // 		if( !bGet1 )	return -1;
// 		return ( d1- d2 );
// 	}
// 
// 	return 0;
// }
InstrumentContainer * InstrumentContainer::m_pSortContainer;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

//默认构造函数
InstrumentContainer::InstrumentContainer()
{
	LOGINIT("FacilityBaseLib");
	m_nType		=	typeNone;
	m_dwDate	=	-1;
	m_nCurrentIndex	=	-1;

	m_nSortVariantID	=	-1/*SLH_INVALID*/;
	m_bSortAscend		=	false;
}
//析构函数
InstrumentContainer::~InstrumentContainer()
{
	Clear();
}

bool InstrumentContainer::lock()
{
	return m_mutex.try_lock();
}

bool InstrumentContainer::unlock()
{
	m_mutex.unlock();
	return true;
}
//添加合约信息类;
int InstrumentContainer::add( InstrumentInfo &newElement )
{
    boost::mutex::scoped_lock l(m_mutex);
	int nIndex = (m_instruments.push_back(newElement),this->size());
	m_map.insert( std::make_pair(string(newElement.get_id()), (nIndex-1)) );//建立索引与合约ID的映射关系
	return nIndex;
}
//当前类型;
bool InstrumentContainer::GetCurrentType( int *pType, string * pDomain, DWORD *pdwDate )
{
	boost::mutex::scoped_lock l(m_mutex);

	if( pType )
		*pType	=	m_nType;
	if( pDomain )
		*pDomain	=	m_strDomain;
	if( pdwDate )
		*pdwDate	=	m_dwDate;
	return true;
}

bool InstrumentContainer::GetPioneerTechDate( DWORD * pdwDate )
{
	InstrumentInfo	info;
	if( GetInstrumentInfo("", &info )
		&& info.m_kdata.size() > 0 )
	{
		*pdwDate	=	info.m_kdata.at(0).TradingDate;
		return true;
	}
	return false;
}

bool InstrumentContainer::GetLatestTechDate( DWORD * pdwDate )
{
	InstrumentInfo	info;

	//获取IF指数的最后时间;
	boost::gregorian::date cur_date = boost::gregorian::day_clock::local_day();
	std::string if_main = boost::str(boost::format("IF%1%%2$02d") % (cur_date.year() % 100) % cur_date.month().as_number());

	if (GetInstrumentInfo(if_main.c_str(), &info)
		&& info.m_kdata.size() > 0 )
	{
		*pdwDate	=	info.m_kdata.at(info.m_kdata.size()-1).TradingDate;
		return true;
	}
	return false;
}

bool InstrumentContainer::GetTechDateArray( std::vector<DWORD> & dwArray )
{
	InstrumentInfo	info;
	if( GetInstrumentInfo( "IF1506", &info ) )
	{
		dwArray.resize( 0);
		for( size_t i=0; i<info.m_kdata.size(); i++ )
			dwArray.push_back( info.m_kdata.at(i).TradingDate );
		return true;
	}
	return false;
}


bool InstrumentContainer::ReRetrieveFromStatic(std::vector<std::string>& instruments, bool bUpToDate )
{
	int	type;
	string	strDomain;
	DWORD	dwDate;
	GetCurrentType( &type, &strDomain, &dwDate );
	if( bUpToDate )
		dwDate	=	-1;
	return RetrieveFromStatic(type, strDomain, instruments, dwDate );
}


bool InstrumentContainer::RetrieveFromStatic(int nType, const std::string& lpszDomain,std::vector<std::string>& instruments, DWORD dwDate )
{
	clear();
	if( nType == InstrumentContainer::typeNone )
	{
		m_nType	=	InstrumentContainer::typeNone;
		return true;
	}
	if( nType < InstrumentContainer::typeMin || nType > InstrumentContainer::typeMax )
		return false;
	m_nType		=	nType;

	m_dwDate	=	dwDate;
	vector<string>	astrSpecify;
	InstrumentContainer& container=InstrumentContainer::get_instance();
	switch( nType )
	{
	case InstrumentContainer::typeAll:
		CopyData(container);
		break;
	case InstrumentContainer::typeIndex:
	case InstrumentContainer::typeA:
	case InstrumentContainer::typeBond:
	case InstrumentContainer::typeFund:
	case InstrumentContainer::typeClassShaa:
	case InstrumentContainer::typeClassShab:
	case InstrumentContainer::typeClassSzna:
	case InstrumentContainer::typeClassSznb:
	case InstrumentContainer::typeClassShabond:
	case InstrumentContainer::typeClassSznbond:
	case InstrumentContainer::typeClassMsmall:
	case InstrumentContainer::typeRight:
		{
			int	nCount	=	0;
			container.resize(container.size() );
			for( size_t i=0; i<container.size(); i++ )
			{
				InstrumentInfo	& info = container.at(i);
//				long	stocktype	=	info.get_type();
				if (strcmp(info.szExchange,lpszDomain.c_str())==0)
				//if( ( typeIndex == nType && CInstrument::typeshIndex == stocktype )
				//	|| ( typeIndex == nType && CInstrument::typeszIndex == stocktype )
				//	|| ( typeA == nType && (CInstrument::typeshA == stocktype || CInstrument::typeszA == stocktype) && !info.IsFund() )
				//	|| ( typeBond == nType && (CInstrument::typeshBond == stocktype || CInstrument::typeszBond == stocktype) )
				//	|| ( typeFund == nType && info.IsFund() )
				//	|| ( typeClassShaa == nType && CInstrument::typeshA == stocktype )
				//	|| ( typeClassShab == nType && CInstrument::typeshB == stocktype )
				//	|| ( typeClassSzna == nType && CInstrument::typeszA == stocktype )
				//	|| ( typeClassSznb == nType && CInstrument::typeszB == stocktype )
				//	|| ( typeClassShabond == nType && CInstrument::typeshBond == stocktype )
				//	|| ( typeClassSznbond == nType && CInstrument::typeszBond == stocktype )
				//	|| ( typeClassMsmall == nType && CInstrument::typeszMsmall == stocktype )
				//	|| ( typeRight == nType && ( CInstrument::typeshRight == stocktype || CInstrument::typeszRight == stocktype) ) )
				{
					add( info );
					nCount	++;
				}
			}
			resize( nCount );
		}
		break;
	case InstrumentContainer::typeStrategy:
		{
			RetrieveSpecify( instruments );
		}
		break;
	case InstrumentContainer::typeGroup:
		{
			if(lpszDomain.length()>0)
			{
				//AfxGetGroupContainer().GetDomainInstruments( lpszDomain, astrSpecify );
				RetrieveSpecify( astrSpecify );
				m_strDomain	=	lpszDomain;
			}
			//else
			//	return AfxGetGroupContainer().GetAllDomainInfo( this, m_dwDate );
		}
		break;
	case InstrumentContainer::typeDomain:
		{
			if(lpszDomain.length()>0 )
			{
				//AfxGetDomainContainer().GetDomainInstruments( lpszDomain, astrSpecify );
				RetrieveSpecify( astrSpecify );
				m_strDomain	=	lpszDomain;
			}
// 			else
// 				return AfxGetDomainContainer().GetAllDomainInfo( this, m_dwDate );
		}
		break;
	default:
		SetMap( );
		return false;
	}
	SetMap( );
	DWORD	dwMainDate = -1;
	if( m_dwDate != dwMainDate )
		OnDataChanged();
	return true;
}

bool InstrumentContainer::RetrieveSpecify( std::vector<std::string> & astr )
{
    boost::mutex::scoped_lock l(m_mutex);

	resize( 0, astr.size());

	int	nCount	=	0;
	for( size_t i=0; i<astr.size(); i++ )
	{
		string	string	=	astr.at(i);
		InstrumentInfo	info;
		if( InstrumentContainer::get_instance().GetInstrumentInfo( string.c_str(), &info ) )
		{
			add( info );
			nCount	++;
		}
	}
	resize( nCount );

	return true;
}

/**
 *
 * \brief 通过合约代码，查找合约信息
 * \detail
 *  首先通过合约ID查找映射中的编号，然后通过编号定位到合约信息
 *  映射是合约ID号与一个整数的MAP映射
 *  合约信息以编号放在一个ARRAY中
 * \return pInfo:合约信息
 * \return pid:编号
 */

bool InstrumentContainer::GetInstrumentInfo( const char * szCode, InstrumentInfo * pInfo, int * pid )
{

    boost::mutex::scoped_lock l(m_mutex);
	if( NULL == szCode || strlen(szCode) <= 0 )
		return false;

	intptr_t pArrayID	=	0;
	std::map<std::string,intptr_t>::iterator it=m_map.find(std::string(szCode));
	if( it!=m_map.end())
	{
		pArrayID=it->second;
        if( ((intptr_t)pArrayID) >= 0 && ((intptr_t)pArrayID) <size() )
		{
            InstrumentInfo	& info	=	at((intptr_t)pArrayID);
			if( pInfo )
				*pInfo	=	info;
			if( pid )
                *pid	=	(intptr_t)pArrayID;
			return true;
		}
	}
	return false;
}
int InstrumentContainer::GetInstrumentIndex(InstrumentInfo * pInfo)
{
    boost::mutex::scoped_lock l(m_mutex);

	if( NULL == pInfo || strlen(pInfo->get_id()) <= 0 )
		return -1;

	intptr_t pArrayID	=	0;
	map<string,intptr_t>::iterator it=m_map.find(string(pInfo->get_id()));
	if( it!=m_map.end())
	{
		pArrayID=it->second;
        if( ((intptr_t)pArrayID) >= 0 && ((intptr_t)pArrayID) < size() )
		{

            return (intptr_t)pArrayID;
		}
	}
	return -1;
}
//设置当前合约;
bool InstrumentContainer::SetCurrentInstrument( const char * szCode )
{
	int	nStockIndex	=	-1;
	InstrumentInfo	info;
	if( GetInstrumentInfo( szCode, &info, &nStockIndex ) )
		return SetCurrentInstrument( nStockIndex );
	else
	{
		boost::mutex::scoped_lock l(m_mutex);
		m_nCurrentIndex			=	-1;
		m_strCurrentStockCode	=	szCode;
		return false;
	}
}

bool InstrumentContainer::SetCurrentInstrument( size_t nStockIndex )
{
    boost::mutex::scoped_lock l(m_mutex);

	if( nStockIndex >= 0 && nStockIndex < size() )
	{
		m_nCurrentIndex	=	nStockIndex;
		return true;
	}
	return false;
}

bool InstrumentContainer::GetCurrentInstrument( InstrumentInfo * pInfo )
{
    boost::mutex::scoped_lock l(m_mutex);

	//assert( pInfo );
	if( m_nCurrentIndex >= 0 && m_nCurrentIndex < size() )
	{
		InstrumentInfo	& info	=	at(m_nCurrentIndex);
		if( pInfo )
			* pInfo	=	info;
		return true;
	}
	else if( m_strCurrentStockCode.length() > 0 )
	{
		InstrumentInfo	info;
		info.set_id( "", m_strCurrentStockCode.c_str() );
		if( pInfo )
			*pInfo	=	info;
		return true;
	}
	return false;
}

bool InstrumentContainer::GetPrevInstrument( InstrumentInfo * pInfo )
{
    boost::mutex::scoped_lock l(m_mutex);

	//assert( pInfo );

	if( size() == 0 )
		return false;

	if( m_nCurrentIndex < 0 || m_nCurrentIndex >= size() )
		m_nCurrentIndex	=	-1;

	if( m_auidSort.size() == size() )
	{
		if( m_nCurrentIndex == -1 )
			m_nCurrentIndex	=	m_auidSort[m_auidSort.size()-1];
		else
		{
			size_t i;
			for( i=0; i<m_auidSort.size(); i++ )
			{
				if( m_nCurrentIndex == (int)m_auidSort[i] )
					break;
			}
			if( i >= m_auidSort.size() || i == 0 )
			{
				m_nCurrentIndex	=	-1;
				return false;
			}
			i --;
			m_nCurrentIndex	= m_auidSort[i];
		}
	}
	else
	{
		if( m_nCurrentIndex < 0 )
			m_nCurrentIndex	=	size()-1;
		else
			m_nCurrentIndex	--;
		if( m_nCurrentIndex < 0 )
		{
			m_nCurrentIndex	=	-1;
			return false;
		}
	}

	if( m_nCurrentIndex >= 0 && m_nCurrentIndex < size() )
	{
		InstrumentInfo	& info	=	at(m_nCurrentIndex);
		if( pInfo )
			* pInfo	=	info;
		return true;
	}
	else
		m_nCurrentIndex	=	-1;

	return false;
}

/**
 * \brief 取得下一个合约
 *
 *
 */
bool InstrumentContainer::GetNextInstrument( InstrumentInfo * pInfo )
{
    boost::mutex::scoped_lock l(m_mutex);

	//assert( pInfo );

	if( size() == 0 )
		return false;

	if( m_nCurrentIndex < 0 || m_nCurrentIndex >= size() )
		m_nCurrentIndex	=	-1;

	if( m_auidSort.size() == size() )
	{
		if( m_nCurrentIndex == -1 )
			m_nCurrentIndex	=	m_auidSort[0];
		else
		{
			size_t i;
			for( i=0; i<m_auidSort.size(); i++ )
			{
				if( m_nCurrentIndex == (int)m_auidSort[i] )
					break;
			}
			i ++;
			if( i >= m_auidSort.size() )
			{
				m_nCurrentIndex	=	-1;
				return false;
			}
			m_nCurrentIndex	= m_auidSort[i];
		}
	}
	else
	{
		if( m_nCurrentIndex < 0 )
			m_nCurrentIndex	=	0;
		else
			m_nCurrentIndex	++;
		if( m_nCurrentIndex >= size() )
		{
			m_nCurrentIndex	=	-1;
			return false;
		}
	}

	if( m_nCurrentIndex >= 0 && m_nCurrentIndex < size() )
	{
		InstrumentInfo	& info	=	at(m_nCurrentIndex);
		if( pInfo )
			* pInfo	=	info;
		return true;
	}
	else
		m_nCurrentIndex	=	-1;

	return false;
}

InstrumentInfo & InstrumentContainer::get_info_by_id( size_t nID )
{
    boost::mutex::scoped_lock l(m_mutex);
	if( nID >= 0 && nID < size() )
	{
		return at( nID );
	}
	return m_infoNull;
}

InstrumentInfo & InstrumentContainer::get_info_by_id(const std::string& szCode, const std::string& exchange_id)
{
	boost::mutex::scoped_lock lck(m_mutex);
	for (std::size_t i = 0; i < this->size(); ++i)
	{
		if (boost::algorithm::iequals(at(i).szExchange, exchange_id) && 
			boost::algorithm::iequals(at(i).get_id(), szCode))
		{
			return at(i);
		}
	}
	return m_infoNull;
}

bool InstrumentContainer::get_info_by_id(const std::string& szCode, InstrumentInfo* pInfo, int * pid /*= nullptr*/)
{
	if (szCode.empty())
		return false;

	std::map<std::string, intptr_t >::iterator mIter= m_map.find(szCode);
	if (mIter != m_map.end())
	{
		intptr_t pArrayID = mIter->second;
		if (((int)pArrayID) >= 0 && ((int)pArrayID) < size())
		{
			InstrumentInfo	& info = at((int)pArrayID);
			if (pInfo)
				*pInfo = info;
			if (pid)
				*pid = (int)pArrayID;
			return true;
		}
	}

	return false;
}

InstrumentInfo & InstrumentContainer::get_info_by_id_sort( size_t nID )
{
    boost::mutex::scoped_lock l(m_mutex);
	if( m_auidSort.size() == size() 
		&& nID >= 0 && nID < size() )
	{
		if( m_auidSort[nID] >= 0 && (int)m_auidSort[nID] < size() )
			return at(m_auidSort[nID]);
	}
	else if( nID >= 0 && nID < size() )
		return at( nID );
	return m_infoNull;
}

InstrumentInfo & InstrumentContainer::average( )
{
	return m_infoAverage;
}

InstrumentInfo & InstrumentContainer::weight_average( )
{
	return m_infoWeightAverage;
}

// bool CInstrumentContainer::Load( CStDatabase * pDB, PROGRESS_CALLBACK fnCallback, void *cookie, int nProgStart, int nProgEnd )
// {
// 	PRINTF("CInstrumentContainer::Load-->Enter");
// 	CSPMutex::Scoped	l(m_mutex);
// 
// 	assert( nProgStart <= nProgEnd );
// 	assert( pDB );
// 	if( nProgStart > nProgEnd || NULL == pDB )
// 		return FALSE;
// 
// 	Clear();
// 
// 	int	nLen	=	pDB->LoadBasetable( *this );
// 	SetMap( );
// 	m_nType		=	typeAll;
// 	m_dwDate	=	-1;
// 
// 	OnDataChanged();
// 	PRINTF("CInstrumentContainer::Load-->Leave");
// 	return TRUE;
// }
InstrumentContainer& InstrumentContainer::get_instance()
{
	static InstrumentContainer g_InstrumentContainer;
	return g_InstrumentContainer;
}
void InstrumentContainer::OnDataChanged( )
{
    //boost::mutex::scoped_lock l(m_mutex);

	DWORD	dateLatest = m_dwDate;
	if( -1 == dateLatest )
		GetLatestTechDate( &dateLatest );
 
	for( size_t i=0; i<size(); i++ )
	{
		InstrumentInfo	& info	=	at(i);
		info.StatBaseIndex( dateLatest );
		info.StatTechIndex( dateLatest );
	}

 	SetAverage( );
}

// bool CInstrumentContainer::ReloadBase( CStDatabase * pDB )
// {
// 	CSPMutex::Scoped	l(m_mutex);
// 
// 	assert( pDB );
// 	if( GetSize() <= 0 || NULL == pDB )
// 		return Load( NULL, NULL );
// 	pDB->LoadBasetable( *this );
// 
// 	OnDataChanged();
// 	return TRUE;
// }

bool InstrumentContainer::SetMap( )
{
    boost::mutex::scoped_lock l(m_mutex);

	m_map.clear();

	if( size() == 0 )
		return true;

	for( size_t i=0; i<size(); i++ )
	{
		InstrumentInfo	&info	=	at(i);
		m_map.insert( make_pair(string(info.get_id()), i) );
	}
	return true;
}

 bool InstrumentContainer::SetAverage( PROGRESS_CALLBACK fnCallback, void *cookie, int nProgStart, int nProgEnd )
 {
	boost::mutex::scoped_lock l(m_mutex);

	assert( nProgStart <= nProgEnd );
	if( nProgStart > nProgEnd )
		return false;

	InstrumentInfo & ave = m_infoAverage;
	InstrumentInfo & wave = m_infoWeightAverage;

	ave.clear();
	wave.clear( );
 
 	ave.set_id("", "ave");
 	ave.set_name( "ave");
 	wave.set_id( "","wave");
 	wave.set_name( "wave" );

//  	ave.m_reporttype	=	instrument::reportUnknown;
//  	wave.m_reporttype	=	CStock::reportUnknown;
 
	float	fTemp	=	0;

	float	dc[100], wdc[100];
	int i = 0;
	for( i=0; i<sizeof(dc)/sizeof(dc[0]); i++ )		dc[i]	=	0.;
	for( i=0; i<sizeof(wdc)/sizeof(wdc[0]); i++ )	wdc[i]	=	(float)0.0001;

	int		nProgressSegment	=	size() / 25;
	float	dProgressRatio		=	( 0 == size() ? 1 : ((float)(nProgEnd - nProgStart))/size() );

	for( std::size_t nCount=0; nCount<size(); nCount++ )
	{
		if( fnCallback && !(nCount % nProgressSegment) )
			fnCallback( PROG_PROGRESS, (int)(nProgStart+nCount*dProgressRatio), NULL, cookie );

		InstrumentInfo & info = at(nCount);

		float	factor	=	1; // (float)CStock::GetReportFactor( info.m_reporttype );

		if( InstrumentData::typeIF == info.get_type() || InstrumentData::typeIH == info.get_type()
			|| InstrumentData::typeTC == info.get_type() || InstrumentData::typeT == info.get_type() )
			continue;

		ave.m_datebase		=	info.m_datebase;
		ave.m_datetech		=	info.m_datetech;
		wave.m_datebase		=	info.m_datebase;
		wave.m_datetech		=	info.m_datetech;
// 
 		long long	w	=	info.Volume;
// 
		/* 平均值 *********************************************************************/
		// ★技术数据;
		int	m = 0, n = 0;
		if( info.LastPrice > 1e-4 )
		{
			ave.LastPrice		=	( ave.LastPrice * dc[m] + info.LastPrice )/(dc[m]+1);			dc[m]	+=	1;
			wave.LastPrice	=	( wave.LastPrice * wdc[n] + info.LastPrice * w )/(wdc[n]+w);	wdc[n]	+=	w;
		}
		m++;	n++;
		if( info.OpenPrice > 1e-4 )
		{
			ave.OpenPrice		=	( ave.OpenPrice * dc[m] + info.OpenPrice )/(dc[m]+1);			dc[m]	+=	1;
			wave.OpenPrice	=	( wave.OpenPrice * wdc[n] + info.OpenPrice * w )/(wdc[n]+w);	wdc[n]	+=	w;
		}
		m++;	n++;
		if( info.ClosePrice > 1e-4 )
		{	
			ave.ClosePrice	=	( ave.ClosePrice * dc[m] + info.ClosePrice )/(dc[m]+1);			dc[m]	+=	1;
			wave.ClosePrice	=	( wave.ClosePrice * wdc[n] + info.ClosePrice * w )/(wdc[n]+w);	wdc[n]	+=	w;
		}
		m++;	n++;
		if( info.HighestPrice > 1e-4 )
		{
			ave.HighestPrice		=	( ave.HighestPrice * dc[m] + info.HighestPrice )/(dc[m]+1);			dc[m]	+=	1;
			wave.HighestPrice	=	( wave.HighestPrice * wdc[n] + info.HighestPrice * w )/(wdc[n]+w);	wdc[n]	+=	w;
		}
		m++;	n++;
		if( info.LowestPrice > 1e-4 )
		{
			ave.LowestPrice		=	( ave.LowestPrice * dc[m] + info.LowestPrice )/(dc[m]+1);			dc[m]	+=	1;
			wave.LowestPrice		=	( wave.LowestPrice * wdc[n] + info.LowestPrice * w )/(wdc[n]+w);	wdc[n]	+=	w;
		}
		m++;	n++;
		if( info.Volume > 1e-4 )
		{
			ave.Volume	=	( ave.Volume * dc[m] + info.Volume )/(dc[m]+1);	dc[m]	+=	1;
		}
		m++;	n++;
		if( info.Turnover > 1e-4 )
		{
			ave.Turnover	=	( ave.Turnover * dc[m] + info.Turnover )/(dc[m]+1);	dc[m]	+=	1;
		}

		for( i=0; i<sizeof(ave.BidPrice)/sizeof(ave.BidPrice[0]); i++ )
		{
			m++;	n++;
			if( info.BidPrice[i] > 1e-4 )
			{
				ave.BidPrice[i]		=	( ave.BidPrice[i] * dc[m] + info.BidPrice[i] )/(dc[m]+1);		dc[m]	+=	1;
				wave.BidPrice[i]		=	( wave.BidPrice[i] * wdc[n] + info.BidPrice[i] )/(wdc[n]+1);	wdc[n]	+=	w;
			}
		}
		for( i=0; i<sizeof(ave.BidVolume)/sizeof(ave.BidVolume[0]); i++ )
		{
			m++;	n++;
			if( info.BidVolume[i] > 1e-4 )
			{
				ave.BidVolume[i]		=	( ave.BidVolume[i] * dc[m] + info.BidVolume[i] )/(dc[m]+1);		dc[m]	+=	1;
				wave.BidVolume[i]	=	( wave.BidVolume[i] * wdc[n] + info.BidVolume[i] )/(wdc[n]+1);	wdc[n]	+=	w;
			}
		}
		for( i=0; i<sizeof(ave.AskPrice)/sizeof(ave.AskPrice[0]); i++ )
		{
			m++;	n++;
			if( info.AskPrice[i] > 1e-4 )
			{
				ave.AskPrice[i]		=	( ave.AskPrice[i] * dc[m] + info.AskPrice[i] )/(dc[m]+1);		dc[m]	+=	1;
				wave.AskPrice[i]	=	( wave.AskPrice[i] * wdc[n] + info.AskPrice[i] )/(wdc[n]+1);	wdc[n]	+=	w;
			}
		}
		for( i=0; i<sizeof(ave.AskVolume)/sizeof(ave.AskVolume[0]); i++ )
		{
			m++;	n++;
			if( info.AskVolume[i] > 1e-4 )
			{
				ave.AskVolume[i]	=	( ave.AskVolume[i] * dc[m] + info.AskVolume[i] )/(dc[m]+1);		dc[m]	+=	1;
				wave.AskVolume[i]	=	( wave.AskVolume[i] * wdc[n] + info.AskVolume[i] )/(wdc[n]+1);	wdc[n]	+=	w;
			}
		}
// 
// 		// ★偿债能力
// 		m++;	n++;
// 		if( fabs(info.m_fRatio_liquidity) > 1e-4 )
// 		{
// 			ave.m_fRatio_liquidity		=	( ave.m_fRatio_liquidity * dc[m] + info.m_fRatio_liquidity )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fRatio_liquidity		=	( wave.m_fRatio_liquidity * wdc[n] + info.m_fRatio_liquidity * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fRatio_quick) > 1e-4 )
// 		{
// 			ave.m_fRatio_quick			=	( ave.m_fRatio_quick * dc[m] + info.m_fRatio_quick )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fRatio_quick			=	( wave.m_fRatio_quick * wdc[n] + info.m_fRatio_quick * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fVelocity_receivables) > 1e-4 )
// 		{
// 			ave.m_fVelocity_receivables	=	( ave.m_fVelocity_receivables * dc[m] + info.m_fVelocity_receivables )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fVelocity_receivables=	( wave.m_fVelocity_receivables * wdc[n] + info.m_fVelocity_receivables * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 		}
// 
// 		// ★经营能力
// 		m++;	n++;
// 		if( fabs(info.m_fVelocity_merchandise) > 1e-4 )
// 		{
// 			ave.m_fVelocity_merchandise	=	( ave.m_fVelocity_merchandise * dc[m] + info.m_fVelocity_merchandise )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fVelocity_merchandise=	( wave.m_fVelocity_merchandise * wdc[n] + info.m_fVelocity_merchandise * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fMain_income) > 1e-4 )
// 		{
// 			ave.m_fMain_income			=	( ave.m_fMain_income * dc[m] + factor*info.m_fMain_income )/(dc[m]+1);		dc[m]	+=	1;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fCash_ps) > 1e-4 )
// 		{
// 			ave.m_fCash_ps				=	( ave.m_fCash_ps * dc[m] + factor*info.m_fCash_ps )/(dc[m]+1);				dc[m]	+=	1;
// 			wave.m_fCash_ps				=	( wave.m_fCash_ps * wdc[n] + factor * info.m_fCash_ps * w )/(wdc[n]+w);		wdc[n]	+=	w;
// 		}
// 
// 		// ★盈利能力
// 		m++;	n++;
// 		if( fabs(info.m_fProfit_margin) > 1e-4 )
// 		{
// 			ave.m_fProfit_margin	=	( ave.m_fProfit_margin * dc[m] + info.m_fProfit_margin )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fProfit_margin	=	( wave.m_fProfit_margin * wdc[n] + info.m_fProfit_margin * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fNetasset_yield) > 1e-4 )
// 		{
// 			ave.m_fNetasset_yield	=	( ave.m_fNetasset_yield * dc[m] + factor*info.m_fNetasset_yield )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fNetasset_yield	=	( wave.m_fNetasset_yield * wdc[n] + factor * info.m_fNetasset_yield * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 		}
// 
// 		// ★资本结构
// 		m++;	n++;
// 		if( info.m_fShare_count_total > 1e-4 )
// 		{
// 			ave.m_fShare_count_total	=	( ave.m_fShare_count_total * dc[m] + info.m_fShare_count_total )/(dc[m]+1);	dc[m]	+=	1;
// 		}
// 		m++;	n++;
// 		if( info.m_fShare_count_a > 1e-4 )
// 		{
// 			ave.m_fShare_count_a		=	( ave.m_fShare_count_a * dc[m] + info.m_fShare_count_a )/(dc[m]+1);			dc[m]	+=	1;
// 		}
// 		m++;	n++;
// 		if( info.m_fShare_count_b > 1e-4 )
// 		{
// 			ave.m_fShare_count_b		=	( ave.m_fShare_count_b * dc[m] + info.m_fShare_count_b )/(dc[m]+1);			dc[m]	+=	1;
// 		}
// 		m++;	n++;
// 		if( info.m_fShare_count_h > 1e-4 )
// 		{
// 			ave.m_fShare_count_h		=	( ave.m_fShare_count_h * dc[m] + info.m_fShare_count_h )/(dc[m]+1);			dc[m]	+=	1;
// 		}
// 		m++;	n++;
// 		if( info.m_fShare_count_national > 1e-4 )
// 		{
// 			ave.m_fShare_count_national	=	( ave.m_fShare_count_national * dc[m] + info.m_fShare_count_national )/(dc[m]+1);	dc[m]	+=	1;
// 		}
// 		m++;	n++;
// 		if( info.m_fShare_count_corp > 1e-4 )
// 		{
// 			ave.m_fShare_count_corp		=	( ave.m_fShare_count_corp * dc[m] + info.m_fShare_count_corp )/(dc[m]+1);	dc[m]	+=	1;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fProfit_psud) > 1e-4 )
// 		{
// 			ave.m_fProfit_psud			=	( ave.m_fProfit_psud * dc[m] + info.m_fProfit_psud )/(dc[m]+1);				dc[m]	+=	1;
// 			wave.m_fProfit_psud			=	( wave.m_fProfit_psud * wdc[n] + info.m_fProfit_psud * w )/(wdc[n]+w);		wdc[n]	+=	w;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fAsset) > 1e-4 )
// 		{
// 			ave.m_fAsset				=	( ave.m_fAsset * dc[m] + info.m_fAsset )/(dc[m]+1);							dc[m]	+=	1;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fRatio_holderright) > 1e-4 )
// 		{
// 			ave.m_fRatio_holderright	=	( ave.m_fRatio_holderright * dc[m] + info.m_fRatio_holderright )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fRatio_holderright	=	( wave.m_fRatio_holderright * wdc[n] + info.m_fRatio_holderright * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fRatio_longdebt) > 1e-4 )
// 		{
// 			ave.m_fRatio_longdebt		=	( ave.m_fRatio_longdebt * dc[m] + info.m_fRatio_longdebt )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fRatio_longdebt		=	( wave.m_fRatio_longdebt * wdc[n] + info.m_fRatio_longdebt * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fRatio_debt) > 1e-4 )
// 		{
// 			ave.m_fRatio_debt			=	( ave.m_fRatio_debt * dc[m] + info.m_fRatio_debt )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fRatio_debt			=	( wave.m_fRatio_debt * wdc[n] + info.m_fRatio_debt * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 		}
// 
// 		// ★投资收益能力
// 		m++;	n++;
// 		if( fabs(info.m_fNetasset_ps) > 1e-4 )
// 		{
// 			ave.m_fNetasset_ps		=	( ave.m_fNetasset_ps * dc[m] + info.m_fNetasset_ps )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fNetasset_ps		=	( wave.m_fNetasset_ps * wdc[n] + info.m_fNetasset_ps * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fNetasset_ps_regulate) > 1e-4 )
// 		{
// 			ave.m_fNetasset_ps_regulate	=	( ave.m_fNetasset_ps_regulate * dc[m] + info.m_fNetasset_ps_regulate )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fNetasset_ps_regulate=	( wave.m_fNetasset_ps_regulate * wdc[n] + info.m_fNetasset_ps_regulate * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fEps) > 1e-4 )
// 		{
// 			ave.m_fEps			=	( ave.m_fEps * dc[m] + factor*info.m_fEps )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fEps			=	( wave.m_fEps * wdc[n] + factor * info.m_fEps * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fEps_deduct) > 1e-4 )
// 		{
// 			ave.m_fEps_deduct	=	( ave.m_fEps_deduct * dc[m] + factor*info.m_fEps_deduct )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fEps_deduct	=	( wave.m_fEps_deduct * wdc[n] + factor * info.m_fEps_deduct * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fNet_profit) > 1e-4 )
// 		{
// 			ave.m_fNet_profit	=	( ave.m_fNet_profit * dc[m] + factor*info.m_fNet_profit )/(dc[m]+1);	dc[m]	+=	1;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fMain_profit) > 1e-4 )
// 		{
// 			ave.m_fMain_profit	=	( ave.m_fMain_profit * dc[m] + factor*info.m_fMain_profit )/(dc[m]+1);	dc[m]	+=	1;
// 		}
// 		m++;	n++;
// 		if( fabs(info.m_fTotal_profit) > 1e-4 )
// 		{
// 			ave.m_fTotal_profit	=	( ave.m_fTotal_profit * dc[m] + factor*info.m_fTotal_profit )/(dc[m]+1);dc[m]	+=	1;
// 		}
// 
// 		// ★增长率
// 		m++;	n++;
// 		ave.m_fProfit_inc	=	( ave.m_fProfit_inc * dc[m] + info.m_fProfit_inc )/(dc[m]+1);			dc[m]	+=	1;
// 		wave.m_fProfit_inc	=	( wave.m_fProfit_inc * wdc[n] + info.m_fProfit_inc * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 
// 		m++;	n++;
// 		ave.m_fIncome_inc	=	( ave.m_fIncome_inc * dc[m] + info.m_fIncome_inc )/(dc[m]+1);			dc[m]	+=	1;
// 		wave.m_fIncome_inc	=	( wave.m_fIncome_inc * wdc[n] + info.m_fIncome_inc * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 
// 		m++;	n++;
// 		ave.m_fAsset_inc	=	( ave.m_fAsset_inc * dc[m] + info.m_fAsset_inc )/(dc[m]+1);			dc[m]	+=	1;
// 		wave.m_fAsset_inc	=	( wave.m_fAsset_inc * wdc[n] + info.m_fAsset_inc * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 
// 		// ★技术数据统计值
// 		m++;	n++;
// 		if( fabs(STKLIB_DATA_INVALID - info.m_fYield_average) > 1e-4 )
// 		{
// 			ave.m_fYield_average	=	( ave.m_fYield_average * dc[m] + info.m_fYield_average )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fYield_average	=	( wave.m_fYield_average * wdc[n] + info.m_fYield_average * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 			m++;	n++;
// 			if( fabs(STKLIB_DATA_INVALID - info.m_fYield_stddev) > 1e-4 )
// 			{
// 				ave.m_fYield_stddev	=	( ave.m_fYield_stddev * dc[m] + info.m_fYield_stddev )/(dc[m]+1);			dc[m]	+=	1;
// 				wave.m_fYield_stddev=	( wave.m_fYield_stddev * wdc[n] + info.m_fYield_stddev * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 			}
// 		}
// 		m++;	n++;
// 		if( fabs(STKLIB_DATA_INVALID - info.m_fBeite) > 1e-4 )
// 		{
// 			ave.m_fBeite	=	( ave.m_fBeite * dc[m] + info.m_fBeite )/(dc[m]+1);			dc[m]	+=	1;
// 			wave.m_fBeite	=	( wave.m_fBeite * wdc[n] + info.m_fBeite * w )/(wdc[n]+w);	wdc[n]	+=	w;
// 		}
// 
		// K线数据;
		m++;	n++;
		if( 0 == nCount )
		{
			m_infoAverage.m_kdata		=	info.m_kdata;
			m_infoWeightAverage.m_kdata	=	info.m_kdata;
		}
		for( int k=info.m_kdata.size()-1; k>=0; k-- )
		{
			KDATA	&	kdInfo	=	info.m_kdata.at(k);
			// 平均值;
			int	nIndex = k;
			if( nIndex >= m_infoAverage.m_kdata.size() || m_infoAverage.m_kdata.at(nIndex).TradingDate != kdInfo.TradingDate )
				nIndex	=	m_infoAverage.m_kdata.GetIndexByDate(kdInfo.TradingDate);
			if( -1 == nIndex )
			{
				KDATA	kdNew;
				memset( &kdNew, 0, sizeof(kdNew) );
				kdNew.TradingDate	=	kdInfo.TradingDate;
				nIndex	=	m_infoAverage.m_kdata.InsertKDataSort(kdNew);
			}
			if( -1 == nIndex )
				continue;
			KDATA	&	kdAve	=	m_infoAverage.m_kdata.at(nIndex);
			kdAve.OpenPrice	=	(kdAve.OpenPrice * dc[m] + kdInfo.OpenPrice)/(dc[m]+1);
			kdAve.HighestPrice	=	(kdAve.HighestPrice * dc[m] + kdInfo.HighestPrice)/(dc[m]+1);
			kdAve.LowestPrice	=	(kdAve.LowestPrice * dc[m] + kdInfo.LowestPrice)/(dc[m]+1);
			kdAve.ClosePrice	=	(kdAve.ClosePrice * dc[m] + kdInfo.ClosePrice)/(dc[m]+1);
			kdAve.Volume	=	(kdAve.Volume * dc[m] + kdInfo.Volume)/(dc[m]+1);
			kdAve.Turnover	=	(kdAve.Turnover * dc[m] + kdInfo.Turnover)/(dc[m]+1);

			// 加权平均值;
			nIndex = k;
			if( nIndex >= m_infoWeightAverage.m_kdata.size() || m_infoWeightAverage.m_kdata.at(nIndex).TradingDate != kdInfo.TradingDate )
				nIndex	=	m_infoWeightAverage.m_kdata.GetIndexByDate(kdInfo.TradingDate);
			if( -1 == nIndex )
			{
				KDATA	kdNew;
				memset( &kdNew, 0, sizeof(kdNew) );
				kdNew.TradingDate	=	kdInfo.TradingDate;
				nIndex	=	m_infoWeightAverage.m_kdata.InsertKDataSort(kdNew);
			}
			if( -1 == nIndex )
				continue;
			KDATA	&	kdWAve		=	m_infoWeightAverage.m_kdata.at(nIndex);
			kdWAve.OpenPrice		=	(kdWAve.OpenPrice * wdc[n] + kdInfo.OpenPrice * w)/(wdc[n]+w);
			kdWAve.HighestPrice		=	(kdWAve.HighestPrice * wdc[n] + kdInfo.HighestPrice * w)/(wdc[n]+w);
			kdWAve.LowestPrice		=	(kdWAve.LowestPrice * wdc[n] + kdInfo.LowestPrice * w)/(wdc[n]+w);
			kdWAve.ClosePrice		=	(kdWAve.ClosePrice * wdc[n] + kdInfo.ClosePrice * w)/(wdc[n]+w);
			kdWAve.Volume			=	(kdWAve.Volume * wdc[n] + kdInfo.Volume * w)/(wdc[n]+w);
			kdWAve.Turnover			=	(kdWAve.Turnover * wdc[n] + kdInfo.Turnover * w)/(wdc[n]+w);
		}
		dc[m]	+=	1;
		wdc[n]	+=	w;

		assert( m <= sizeof(dc)/sizeof(dc[0]) );
		assert( n <= sizeof(wdc)/sizeof(wdc[0]) );

	}

	if( fnCallback )
		fnCallback( PROG_PROGRESS, nProgEnd, NULL, cookie );

    return true;
}

bool InstrumentContainer::Clear( )
{
    boost::mutex::scoped_lock l(m_mutex);

	ClearVariantSaveValue( );

	// WARNING: Cannot clear this m_nCurrentStock	=	-1;
	// WARNING: Cannot clear this m_strCurrentStockCode.Empty();
	m_nType		=	typeNone;
	m_strDomain.clear();
	m_dwDate = -1;
	clear();
	m_map.clear( );
	m_infoAverage.clear( );
	m_infoWeightAverage.clear( );

	m_auidSort.clear();
	return true;
}

void InstrumentContainer::CopyData( InstrumentContainer & src )
{
    boost::mutex::scoped_lock l(m_mutex);

	resize( src.size() );
	for( size_t i=0; i<src.size(); i++ )
	{
		InstrumentInfo	& info	=	src.at(i);
		this->operator[](i)= info;
	}
}

int InstrumentContainer::SortFunction(const void *s1,const void *s2)
{
	InstrumentInfo *pStock1 = (InstrumentInfo *)s1;
	InstrumentInfo *pStock2 = (InstrumentInfo *)s2;

	if( NULL == pStock2 )
		return 1;

	if( NULL == pStock1 )
		return -1;

	if( NULL == InstrumentContainer::m_pSortContainer )
		return 1;

// 	int nRet = AfxCompareVariantValue(	CInstrumentContainer::m_pSortContainer->m_nSortVariantID, *pStock1, *pStock2,
// 		CInstrumentContainer::m_pSortContainer );
// 	if( CInstrumentContainer::m_pSortContainer->m_bSortAscend )
// 		return nRet;
// 	if( nRet > 0 )
// 		return -1;
// 	else if( nRet < 0 )
// 		return 1;
	return 0;
}


int InstrumentContainer::StockInfoCompareFunc( const void *s1,const void *s2, InstrumentContainer * pContainer, int nSortVariantID )
{
	InstrumentInfo *pStock1 = (InstrumentInfo *)s1;
	InstrumentInfo *pStock2 = (InstrumentInfo *)s2;

	if( NULL == pStock2 )
		return 1;

	if( NULL == pStock1 )
		return -1;
	return 0;
	//return AfxCompareVariantValue(	nSortVariantID, *pStock1, *pStock2, pContainer );
}


bool InstrumentContainer::Sort( int nSortVariantID, bool bAscend )
{
    boost::mutex::scoped_lock l(m_mutex);

	m_auidSort.clear();	// if call this Sort(...), then not use m_auidSort

	InstrumentContainer::m_pSortContainer	=	this;
	m_nSortVariantID	=	nSortVariantID;
	m_bSortAscend		=	bAscend;

// 	if( NULL != GetData() )
// 		qsort( GetData(), size(), sizeof(CInstrumentInfo), SortFunction );
	return true;
}

void InstrumentContainer::SetSortID( vector<DWORD> & auidsort )
{
    boost::mutex::scoped_lock l(m_mutex);

	m_auidSort.clear();
	m_auidSort.assign( auidsort.begin(),auidsort.end() );
}


bool InstrumentContainer::GetMultiSortIDArray( std::vector<DWORD> & adwSortID, int lStockType, UINT nSLH, bool bAsc, size_t nCount )
{
   // boost::mutex::scoped_lock l(m_mutex);

	//assert( nCount > 0 && nSLH >= SLH_MIN && nSLH <= SLH_MAX );
	if (nCount <= SLH_MIN || nSLH < 1 || nSLH > SLH_MAX)
		return false;

	adwSortID.clear();

	for( size_t n=0; n<nCount; n++ )
	{
		int		nMinMaxIndex	=	-1;
		double	dMinMaxValue	=	0;
		bool	bInited	=	false;
		for( size_t i=0; i<size(); i++ )
		{
			InstrumentInfo & info	=	at(i);

			// 股票类型;
			if( info.get_type() == typeNone )
				continue;

			// 如果加过，则继续寻找下一个;
			size_t k;
			for( k=0; k<adwSortID.size(); k++ )
			{
				if( adwSortID[k] == (DWORD)i )
					break;
			}
			if( k != adwSortID.size() )
				continue;

			// 判断大小;
			double	dValue	=	0;
			if( AfxGetVariantValue( nSLH, info, &dValue, NULL ))
			{
				if( !bInited )
				{
					nMinMaxIndex	=	i;
					dMinMaxValue	=	dValue;
					bInited	=	true;
				}
				if( bAsc && dValue < dMinMaxValue )
				{
					nMinMaxIndex	=	i;
					dMinMaxValue	=	dValue;
				}
				if( !bAsc && dValue > dMinMaxValue )
				{
					nMinMaxIndex	=	(DWORD)i;
					dMinMaxValue	=	dValue;
				}
			}
		}

		if( -1 == nMinMaxIndex )
			break;
		adwSortID.push_back( nMinMaxIndex );
	}

	return true;
}

bool InstrumentContainer::GetVariantSaveValue( double *pValue, UINT nVariantID, InstrumentInfo &info, bool *pNoValue )
{
    boost::mutex::scoped_lock l(m_mutex);

	intptr_t pArrayID	=	NULL;
	map<string,intptr_t >::iterator it=m_map.find(string(info.get_id()));
	if( m_map.end()==it )
		return false;
	pArrayID=it->second;
    int	nIndex	=	(intptr_t)pArrayID;
	if( nIndex >= 0 && nIndex < (int)m_aptrSaveValueArray.size() )
	{
		vector<void* > * pArray = (vector<void* > *)m_aptrSaveValueArray.at( nIndex );
		if( pArray )
		{
			VARIANT_SAVEVALUE * pSave = NULL;
			for( size_t j=0; j<pArray->size(); j++ )
			{
				pSave = (VARIANT_SAVEVALUE *) pArray->at(j);
				if( pSave->nVariantID == nVariantID )
				{
					if( pValue )	*pValue		=	pSave->Value;
					if( pNoValue )	*pNoValue	=	pSave->bNoValue;
					return true;
				}
			}
		}
	}

	return false;
}

void InstrumentContainer::SetVariantSaveValue( double Value, UINT nVariantID, InstrumentInfo &info, bool bNoValue )
{
	boost::mutex::scoped_lock l(m_mutex);

	intptr_t pArrayID	=	NULL;
	map<string,intptr_t >::iterator it=m_map.find(string(info.get_id()));
	if( m_map.end()==it )
		return ;
	pArrayID=it->second;
	// alloc for m_aptrSaveValueArray
	if( m_aptrSaveValueArray.size() == 0 )
	{
		m_aptrSaveValueArray.resize( size() );
		for( size_t i=0; i<m_aptrSaveValueArray.size(); i++ )
			m_aptrSaveValueArray[i]= NULL;
	}

    int	nIndex	=	(intptr_t)pArrayID;
	if( nIndex >= 0 && nIndex < (int)m_aptrSaveValueArray.size() )
	{
		vector<void*> * pArray = (vector<void*> *)m_aptrSaveValueArray.at( nIndex );
		if( NULL == pArray )
		{
			pArray	=	new	vector<void*>;
			m_aptrSaveValueArray[nIndex]=pArray;
		}

		// 如果已经存在，覆盖之
		for( size_t j=0; j<pArray->size(); j++ )
		{
			VARIANT_SAVEVALUE * pSave = (VARIANT_SAVEVALUE *) pArray->at(j);
			if( pSave->nVariantID == nVariantID )
			{
				pSave->Value	=	Value;
				pSave->bNoValue	=	bNoValue;
				return;
			}
		}

		// 加入新的
		VARIANT_SAVEVALUE * pSaveValue = new VARIANT_SAVEVALUE;
		pSaveValue->nVariantID	=	nVariantID;
		pSaveValue->Value		=	Value;
		pSaveValue->bNoValue	=	bNoValue;
		pArray->push_back( pSaveValue );
	}
}

void InstrumentContainer::ClearVariantSaveValue( )
{
    //boost::mutex::scoped_lock l(m_mutex);

	for( size_t i=0; i<m_aptrSaveValueArray.size(); i++ )
	{
		std::vector<void* > * pArray = (std::vector<void* > *)m_aptrSaveValueArray.at( i );
		if( pArray )
		{
			for( size_t j=0; j<pArray->size(); j++ )
				delete	pArray->at(j);
			delete	pArray;
		}
	}
	m_aptrSaveValueArray.clear();
}

bool InstrumentContainer::update( InstrumentContainer &container,const Tick * pReport, bool bAddIfNotExist, Tick * pReportLast/*=NULL */ )
{
	if( nullptr == pReport )
		return false;

	bool bResult = false;
	Tick	reportLast = {};

	int	id = 0;
	if( container.GetInstrumentInfo( pReport->szCode, NULL, &id ) )
	{
		InstrumentInfo	& info	=	container.at(id);
		reportLast	=	info.m_reportLatest;
		bResult=InstrumentInfo::update(info, pReport);
	}
	else if( bAddIfNotExist && strlen(pReport->szCode)>0 )
	{
		InstrumentInfo	info = {};
		info.set_id( pReport->szExchange, pReport->szCode );
		if( InstrumentInfo::update( info, pReport ) )
		{
			container.add( info );
			bResult = true;
		}
	}

	if( pReportLast )
		memcpy( pReportLast, &reportLast, sizeof(reportLast) );

	return bResult;
}

bool InstrumentContainer::update(InstrumentContainer &container, boost::shared_ptr<BASEDATA> pBasedata, bool bAddIfNotExist)
{
	if( nullptr == pBasedata )
		return false;
	int	id = 0;
	if( container.GetInstrumentInfo( pBasedata->szCode, nullptr, &id ) )
	{
		container.lock();
		InstrumentInfo	& info	=	container.at(id);
		InstrumentInfo::update( info, pBasedata );
		container.unlock();
	}
	else if( bAddIfNotExist && strlen(pBasedata->szCode)>0 )
	{
		InstrumentInfo	info;
		info.set_id( pBasedata->szExchange, pBasedata->szCode );
		if( InstrumentInfo::update( info, pBasedata ) )
		{
			container.add( info );
		}
	}
	else
	{
		return false;
	}
	return true;
}

bool InstrumentContainer::update(InstrumentContainer & container, Instrument * pBasedata, bool bAddIfNotExist, Instrument * pBasedataLast)
{
	if (NULL == pBasedata)
		return false;

	Tick	reportLast = {};

	int	id = 0;
	if (container.GetInstrumentInfo(pBasedata->InstrumentID.c_str(), NULL, &id))
	{
		container.lock();

		InstrumentInfo	& info = container.at(id);
		reportLast = info.m_reportLatest;
		InstrumentInfo::update(info, pBasedata);

		container.unlock();
	}
	else if (bAddIfNotExist && strlen(pBasedata->InstrumentID.c_str())>0)
	{
		InstrumentInfo	info = {};
		info.set_id(pBasedata->ExchangeID.c_str(), pBasedata->InstrumentID.c_str());
		if (InstrumentInfo::update(info, pBasedata))
		{
			container.add(info);
			int i = 0;
			i++;
		}
	}

	if (pBasedataLast)
		memcpy(pBasedataLast, &reportLast, sizeof(reportLast));

	return true;
}

bool InstrumentContainer::update(InstrumentContainer &container, const std::string& InstrumentID, KdataContainer& kdata)
{
	container.lock();

	int	id = 0;
	if (ktypeDay == kdata.GetKType()
		&& container.get_info_by_id(InstrumentID, nullptr, &id))
	{
		InstrumentInfo	& info = container.at(id);
		if (kdata.size() > InstrumentConfig::GetInstance().GetCacheDays())
		{
			// 只使用AfxGetProfile().GetCacheDays()天的数据
			KdataContainer	temp(kdata.GetKType());
			for (int i = kdata.size() - InstrumentConfig::GetInstance().GetCacheDays(); i < (int)kdata.size(); i++)
				temp.push_back(kdata.at(i));
			info.m_kdata.MergeKData(&temp);
		}
		else
			info.m_kdata.MergeKData(&kdata);


		// 指数涨跌家数;
		int nSize = info.m_kdata.size();
		if (nSize > 0)
		{
			info.m_dwAdvance = info.m_kdata.at(nSize - 1).Advance;
			info.m_dwDecline = info.m_kdata.at(nSize - 1).Decline;
		}
	}
	container.unlock();
    return true;
}

char* InstrumentContainer::GetExhcnageIDByInstrumentID( const char* insID )
{
	for (size_t i=0;i<m_instruments.size();i++)
	{
		InstrumentInfo	& info	=	m_instruments[i];
		if (0==strcmp(info.szCode,insID))
		{
			return info.szExchange;
		}
	}
	return "SHFE";
}

InstrumentInfo& InstrumentContainer::at( size_t idx )
{
	return m_instruments[idx];
}

bool InstrumentContainer::get_names( std::vector<std::string>& names,bool bIdOrNames/*=true*/ )
{
	if (!names.empty())
	{
		names.clear();
	}
	boost::mutex::scoped_lock lck(m_mutex);
	for (std::size_t i=0;i<this->size();++i)
	{
		names.push_back(bIdOrNames?at(i).szCode: at(i).szName);
	}
	return true;
}

bool InstrumentContainer::get_names_by_exchange(std::vector<std::string>& names, const std::string & exchange, bool bIdOrNames/* = true*/)
{
	if (!names.empty())
	{
		names.clear();
	}
	boost::mutex::scoped_lock lck(m_mutex);
	for (std::size_t i = 0;i<this->size();++i)
	{
		if (boost::algorithm::iequals(at(i).szExchange,exchange))
		{
			names.push_back(bIdOrNames?at(i).szCode:at(i).szName);
		}
	}
	return true;
}

std::size_t InstrumentContainer::size() const
{
	return m_instruments.size();
}
std::size_t InstrumentContainer::size()
{
	return m_instruments.size();
}

bool InstrumentContainer::get_names_by_product(std::vector<std::string>& names, const std::string& product, bool bIdOrNames /*= true*/)
{
	if (!names.empty())
	{
		names.clear();
	}
	boost::mutex::scoped_lock lck(m_mutex);
	for (std::size_t i = 0; i < this->size(); ++i)
	{
		if (boost::algorithm::iequals(at(i).ProductID, product))
		{
			names.push_back(bIdOrNames ? at(i).szCode : at(i).szName);
		}
	}
	return true;
}

void InstrumentContainer::push_back(InstrumentInfo& val)
{
	m_instruments.push_back(val);
}

InstrumentInfo& InstrumentContainer::operator[](std::size_t t)
{
	return m_instruments[t];
}

void InstrumentContainer::resize(size_t nNewSize, int nGrowBy /*= -1*/)
{
	m_instruments.resize(nNewSize);
}

bool InstrumentContainer::update_status(boost::shared_ptr<InstStatus> instStatus)
{
	if (!instStatus)
	{
		return false;
	}
	InstrumentInfo& info = get_info_by_id(instStatus->InstrumentID,instStatus->ExchangeID);
	if (info.is_valid())
	{
		info.m_status = instStatus;
		return true;
	}
	boost::mutex::scoped_lock lck(m_mutex);
	for (std::size_t i = 0; i < this->size(); ++i)
	{
		if (boost::algorithm::iequals(at(i).ProductID, instStatus->InstrumentID))
		{
			at(i).m_status = instStatus;
		}
	}
	return true;
}

void InstrumentContainer::SetType(int nType)
{
	m_nType = nType;
}

void InstrumentContainer::SetDate(DWORD dwDate)
{
	m_dwDate = dwDate;
}












